<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
    // call方法: Function的原型对象上
    Function.prototype.call = function (thisObj,  ...args) {
      // this就是调用call方法的函数对象
      // this(...args)

      // 处理thisObj的特殊值
      if (thisObj===null || thisObj===undefined) {
        return this(...args)
        // thisObj = window
      }


      // 将this函数添加为thisObj的临时方法
      thisObj.tempFn = this
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法属性
      delete thisObj.tempFn
      // 返回方法执行的结果
      return result
    }

    Function.prototype.apply = function (thisObj,  args) {
      // 处理thisObj的特殊值
      if (thisObj===null || thisObj===undefined) {
        return this(...args)
        // thisObj = window
      }


      // 将this函数添加为thisObj的临时方法
      thisObj.tempFn = this
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法属性
      delete thisObj.tempFn
      // 返回方法执行的结果
      return result
    }


    // 返回一个新函数, 新函数内部会原函数, 且指定原函数中的this为bind的第一个参数
    // 也就是只调用bind返回的新函数, 原函数就会执行, 且this总bind的第一个参数
    // bind不仅可以绑定this, 还能绑定参数
    Function.prototype.bind = function (thisObj, ...args) {
      // this就是原函数
      return (...args2) => {
        this.call(thisObj, ...args, ...args2)
      }
    }




    function call(f, thisObj,  ...args) {
       // 处理thisObj的特殊值
       if (thisObj===null || thisObj===undefined) {
        return f(...args)
        // thisObj = window
      }


      // 将this函数添加为thisObj的临时方法
      thisObj.tempFn = f
      // 通过thisObj来调用这个方法
      const result = thisObj.tempFn(...args)
      // 删除这个方法属性
      delete thisObj.tempFn
      // 返回方法执行的结果
      return result
    }
  </script>

  <script>
    var m = 2
    function fn(a, b) {
      console.log(this, a, b);
      return a + b
    }
    const obj = {m: 1}

    // 返回一个新函数, 新函数内部会原函数, 且指定原函数中的this为bind的第一个参数
    // 也就是只调用bind返回的新函数, 原函数就会执行, 且this总bind的第一个参数
    // bind不仅可以绑定this, 还能绑定参数
    console.log(fn.bind(obj)(2, 3))
    console.log(fn.bind(obj, 4)(2, 3))
    console.log(fn.bind(obj, 4, 5)(2, 3))


    // console.log(fn.call(obj, 2, 3))
    // console.log(fn.call(null, 2, 3))
    // console.log(fn.call(undefined, 2, 3))

    // console.log(call(fn, obj, 2, 3))
    // console.log(call(fn, null, 2, 3))
    // console.log(call(fn, undefined, 2, 3))


    // console.log(fn.apply(obj, [2, 3]))
    // console.log(fn.apply(null, [2, 3]))
    // console.log(fn.apply(undefined, [2, 3]))


    
    
  </script>
</body>
</html>